/**********************************************************************************************/
/* FBL_Convert.cpp 	                                                      					  */
/*                                                                       					  */
/* Copyright Paradigma, 1993-2006															  */
/* All Rights Reserved                                                   					  */
/**********************************************************************************************/

#include <VShared/FBL/publ/Headers/StdAfx.h>

#include <VShared/FBL/publ/Interfaces/FBL_I_Value.h>
#include <VShared/FBL/publ/Values/FBL_Convert.h>
#include <VShared/FBL/publ/Values/FBL_type_traits.h>
#include <VShared/FBL/publ/Factories/FBL_Value_Factory.h>

#include <stdlib.h>
#include <stdio.h>


/**********************************************************************************************/
FBL_Begin_Namespace


/**********************************************************************************************/
// Date and time convert functions.
extern void Convert_str_date	( const I_Value* inValue, I_Value* outValue );
extern void Convert_str_time	( const I_Value* inValue, I_Value* outValue );
extern void Convert_str_datetime( const I_Value* inValue, I_Value* outValue );


/**********************************************************************************************/
// Date and time convert functions.
extern void Convert_Date_str	( const I_Value* inValue, I_Value* outValue );
extern void Convert_Time_str	( const I_Value* inValue, I_Value* outValue );
extern void Convert_DateTime_str( const I_Value* inValue, I_Value* outValue );

extern void Convert_str_str		( const I_Value* inValue, I_Value* outValue );

/**********************************************************************************************/
// This one function do conversion for all numeric fundamental C types.
//
template<class T1, class T2>
void Convert_T_T( const I_Value* inValue, I_Value* outValue )
{
	*(T2*) outValue->begin() = (T2) *(T1*) inValue->begin();
}


#pragma mark -


/**********************************************************************************************/
template<class T> 
void Convert_str_T( const I_Value* inValue, I_Value* outValue )
{
	type_traits<T>::from_str( (const UChar*)inValue->begin(), (T*)outValue->begin() );
}


/**********************************************************************************************/
template<class T> 
void Convert_T_str( const I_Value* inValue, I_Value* outValue )  
{
	char* ps = const_cast<char*>( outValue->begin() );
	char* pe = (char*)type_traits<T>::to_str( (T*)inValue->begin(), (UChar*)ps );
	outValue->put_ByteLength( ulong( pe - ps ) );
}


/**********************************************************************************************/
// this macro convertion from inType type to other specified type:
//
#define ARR_For(name, T)\
CONVERT_FUNC_PTR Arr_##name[33] =												\
{																				\
	NULL, 										/*  kTypeEmpty		*/			\
	NULL,										/*  kTypeEnum 		*/			\
	Convert_T_T<T, bool>,						/*	kTypeBoolean	*/			\
	Convert_T_T<T, uchar>,						/*	kTypeByte		*/			\
	Convert_T_T<T, short>,						/*	kTypeShort		*/			\
	Convert_T_T<T, ushort>,						/*	kTypeUShort		*/			\
	Convert_T_T<T, long>,						/*	kTypeMedium		*/			\
	Convert_T_T<T, ulong>,						/*	kTypeUMedium	*/			\
	Convert_T_T<T, long>,						/*	kTypeLong		*/			\
	Convert_T_T<T, ulong>,						/*	kTypeULong		*/			\
	Convert_T_T<T, llong>,						/*	kTypeLLong		*/			\
	Convert_T_T<T, ullong>,						/*	kTypeULLong		*/			\
																				\
	Convert_T_T<T, float>,						/*	kTypeFloat		*/			\
	Convert_T_T<T, double>,						/*	kTypeDouble		*/			\
	NULL,										/*	kTypeLDouble	*/			\
	NULL,										/*	kTypeDecimal	*/			\
																				\
	Convert_T_T<T, long>,						/*	kTypeDate		*/			\
	Convert_T_T<T, ulong>,						/*	kTypeTime		*/			\
	Convert_T_T<T, llong>,						/*	kTypeDateTime	*/			\
																				\
	Convert_T_str<T>,							/*	kTypeString		*/			\
	Convert_T_str<T>,							/*	kTypeVarChar	*/			\
																				\
	NULL,										/*	kTypeFixedBinary*/			\
	NULL,										/*	kTypeVarBinary	*/			\
																				\
	NULL,										/*	kTypeBLOB		*/			\
	Convert_T_str<T>,							/*	kTypeText		*/			\
	NULL,										/*	kTypePicture	*/			\
	NULL,										/*	kTypeSound		*/			\
	NULL,										/*	kTypeMovie		*/			\
																				\
	Convert_T_T<T, ulong>,						/*	kTypeRecID		*/			\
	Convert_T_T<T, ullong>,						/*	kTypeOID		*/			\
	Convert_T_T<T, ulong>,						/*	kTypeObjectPtr	*/			\
	Convert_T_T<T, ullong>,						/*	kTypeObjectsPtr	*/			\
	Convert_T_T<T, ullong>						/*	kTypeTimeStamp	*/			\
}													


/**********************************************************************************************/
ARR_For(Bool,bool);
ARR_For(Byte,uchar);
ARR_For(Short,short);
ARR_For(UShort,ushort);
ARR_For(Long,long);
ARR_For(ULong,ulong);
ARR_For(Float,float);
ARR_For(Double,double);
ARR_For(LLong,llong);
ARR_For(ULLong,ullong);
ARR_For(Date,long);
ARR_For(Time,ulong);
ARR_For(DateTime,llong);
//ARR_For(ULLong,ullong);
//ARR_For(LDouble,ldouble);


/**********************************************************************************************/
	// this array convertion from string to other specified type:
CONVERT_FUNC_PTR Arr_Str[33] =		
{																				\
	NULL, 										/*  kTypeEmpty		*/			\
	NULL,										/*  kTypeEnum 		*/			\
	Convert_str_T<bool>,						/*	kTypeBoolean	*/			\
	Convert_str_T<uchar>,						/*	kTypeByte		*/			\
	Convert_str_T<short>,						/*	kTypeShort		*/			\
	Convert_str_T<ushort>,						/*	kTypeUShort		*/			\
	Convert_str_T<long>,						/*	kTypeMedium		*/			\
	Convert_str_T<ulong>,						/*	kTypeUMedium	*/			\
	Convert_str_T<long>,						/*	kTypeLong		*/			\
	Convert_str_T<ulong>,						/*	kTypeULong		*/			\
	Convert_str_T<llong>,						/*	kTypeLLong		*/			\
	Convert_str_T<ullong>,						/*	kTypeULLong		*/			\
																				\
	Convert_str_T<float>,						/*	kTypeFloat		*/			\
	Convert_str_T<double>,						/*	kTypeDouble		*/			\
	NULL,										/*	kTypeLDouble	*/			\
	NULL,										/*	kTypeDecimal	*/			\
																				\
	Convert_str_date,							/*	kTypeDate		*/			\
	Convert_str_time,							/*	kTypeTime		*/			\
	Convert_str_datetime,						/*	kTypeDateTime	*/			\
																				\
	Convert_str_str,							/*	kTypeString		*/			\
	Convert_str_str,							/*	kTypeVarChar	*/			\
																				\
	NULL,										/*	kTypeFixedBinary*/			\
	NULL,										/*	kTypeVarBinary	*/			\
																				\
	NULL,										/*	kTypeBLOB		*/			\
	Convert_str_str,							/*	kTypeText		*/			\
	NULL,										/*	kTypePicture	*/			\
	NULL,										/*	kTypeSound		*/			\
	NULL,										/*	kTypeMovie		*/			\
																				\
	Convert_str_T<ulong>,						/*	kTypeRecID		*/			\
	Convert_str_T<ullong>,						/*	kTypeOID		*/			\
	Convert_str_T<ulong>,						/*	kTypeObjectPtr	*/			\
	Convert_str_T<ullong>,						/*	kTypeObjectsPtr	*/			\
	Convert_str_T<ullong>						/*	kTypeTimeStamp	*/
};													
										

/**********************************************************************************************/
// this is Matrix of convertion from all type to all type:
CONVERT_FUNC_PTR* Arr_T_T[33] =		
{																				
	NULL, 										/*  kTypeEmpty		*/			
	NULL,										/*  kTypeEnum 		*/			
	Arr_Bool,									/*	kTypeBoolean	*/			
	Arr_Byte,									/*	kTypeByte		*/			
	Arr_Short,									/*	kTypeShort		*/			
	Arr_UShort,									/*	kTypeUShort		*/			
	Arr_Long,									/*	kTypeMedium		*/			
	Arr_ULong,									/*	kTypeUMedium	*/			
	Arr_Long,									/*	kTypeLong		*/			
	Arr_ULong,									/*	kTypeULong		*/			
	Arr_LLong,									/*	kTypeLLong		*/			
	Arr_ULLong,									/*	kTypeULLong		*/			
																				
	Arr_Float,									/*	kTypeFloat		*/			
	Arr_Double,									/*	kTypeDouble		*/			
	NULL,										/*	kTypeLDouble	*/			
	NULL,										/*	kTypeDecimal	*/			
																				
	Arr_Date,									/*	kTypeDate		*/			
	Arr_Time,									/*	kTypeTime		*/			
	Arr_DateTime,								/*	kTypeDateTime	*/			
																				
	Arr_Str,									/*	kTypeString		*/			
	Arr_Str,									/*	kTypeVarChar	*/			
																				
	NULL,										/*	kTypeFixedBinary*/			
	NULL,										/*	kTypeVarBinary	*/			
																				
	NULL,										/*	kTypeBLOB		*/			
	Arr_Str,									/*	kTypeText		*/			
	NULL,										/*	kTypePicture	*/			
	NULL,										/*	kTypeSound		*/			
	NULL,										/*	kTypeMovie		*/			
																				
	Arr_ULong,									/*	kTypeRecID		*/			
	Arr_ULLong,									/*	kTypeOID		*/			
	Arr_ULong,									/*	kTypeObjectPtr	*/			
	Arr_ULLong,									/*	kTypeObjectsPtr	*/			
	Arr_ULLong									/*	kTypeTimeStamp	*/
};													
										

#pragma mark -
 

/**********************************************************************************************/
bool ConvertValue(
	ulong inValueType, 
	ulong outValueType, 
	const I_Value*	inValue,
		  I_Value*	outValue )
{
	CONVERT_FUNC_PTR pConvertFunc = Arr_T_T[inValueType][outValueType];
	
	if( pConvertFunc )
	{
		pConvertFunc( inValue, outValue );
		return true;
	}
	else
	{
		FBL_CHECK( pConvertFunc != NULL );
		return false;
	}
}


/**********************************************************************************************/
bool ConvertValue(
	const I_Value*	inValue,
		  I_Value*	outValue )
{
	return ConvertValue( 
				inValue->get_Type(), outValue->get_Type(),
				inValue, 			outValue );
}


/**********************************************************************************************/
// if inValue is NULL, then we create new value with Nullable flag.
// New value on construction get NULL value.
//
I_Value_Ptr ConvertValue(
	const I_Value& inValue,
	VALUE_TYPE inResultType )
{
	bool IsNull = inValue.get_IsNull();

	// Create Value of required type:
	FieldAttributes flags = IsNull ? fNullable : fNone;

	tslen Len = 0;
	if( inValue.get_Category() == vcString )
		Len = static_cast<tslen>(inValue.get_Length());
	else
		Len = static_cast<tslen>(inValue.get_MaxChars());

	I_Value_Ptr result = internal::CreateValue( inResultType, static_cast<ushort>(flags), &Len );

	if( inValue.get_IsRemote() )
		result->put_IsRemote( true );

	if( IsNull )
		return result; // it is 'NULL' value.

	if( result )
	{
		if( ConvertValue( &inValue, result.get() ) )
			result->put_IsNull( false );
		else
			result.SetNull(); // delete new value.
	}

	return result;
}


#pragma mark -


/**********************************************************************************************/
TypeConverter::TypeConverter( ulong inTypeA, ulong inTypeB ) throw()
{
	mFuncPtr = Arr_T_T[inTypeA][inTypeB];
}


/**********************************************************************************************/
int SmartCompare( Const_I_Value_Ptr inFirstVal, Const_I_Value_Ptr inSecondVal )
{		
	int result;
			
	// Convert "least" value to "greatest" first
	// Because Compare does not care about types - it must be just the same.
	//
	
	VALUE_TYPE frstValueType = inFirstVal->get_Type();
	VALUE_TYPE scndValueType = inSecondVal->get_Type();
	
	if( frstValueType != scndValueType )
	{
		if( inFirstVal->get_MaxChars() > inSecondVal->get_MaxChars() )
		{
			I_Value_Ptr pConvertedValue = ConvertValue( *inSecondVal, frstValueType );
			result = inFirstVal->Compare( *pConvertedValue );
		}
		else
		{
			I_Value_Ptr pConvertedValue = ConvertValue( *inFirstVal, scndValueType );
			result = pConvertedValue->Compare( *inSecondVal );					
		}
	}
	else
		result = inFirstVal->Compare( *inSecondVal );
	
	return result;
}


/**********************************************************************************************/
CONVERT_FUNC_PTR FBL_SHARED_EXP get_Convertor( ulong inValueType, ulong outValueType )
{
	if( Arr_T_T[inValueType] == NULL )
		return NULL;
	else
		return Arr_T_T[inValueType][outValueType];
}


/**********************************************************************************************/
FBL_End_Namespace
